# install dplyr

install.packages("dplyr")
Error in install.packages : Updating loaded packages
install.packages("ggplot2")
Error in install.packages : Updating loaded packages
#load in dplyr

library(dplyr)
library(ggplot2)
library(datasets)
# read the csv files

lahman_people <- read.csv("lahman_people.csv")
savant_data <- read.csv("savant_data_2021_2023.csv")
install.packages("ggplot2")
trying URL 'https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.4/ggplot2_3.5.1.tgz'
Content type 'application/x-gzip' length 4974305 bytes (4.7 MB)
==================================================
downloaded 4.7 MB

The downloaded binary packages are in
    /var/folders/zh/vh4pt2mx1z56qx417_jrsbp00000gn/T//RtmpaTOuiW/downloaded_packages
install.packages("dplyr")
Error in install.packages : Updating loaded packages
head(lahman_people)
head(savant_data)
install.packages("dplyr")
trying URL 'https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.4/dplyr_1.1.4.tgz'
Content type 'application/x-gzip' length 1599250 bytes (1.5 MB)
==================================================
downloaded 1.5 MB

The downloaded binary packages are in
    /var/folders/zh/vh4pt2mx1z56qx417_jrsbp00000gn/T//RtmpaTOuiW/downloaded_packages
plate_appearances <- 
    # start with the savant data
    savant_data  %>%
    # we will group by batter, season, game, and at bat and preserve the 
    group_by(
        batter,
        game_year,
        game_pk,
        at_bat_number
    ) %>%
    summarise() %>%
    ungroup() %>%
    # now we have just unique batter, season, game, and at bat observations
    # but, we need to count how many of those there are each season
    # so, we will do another group by and summarise
    group_by(
        batter,
        game_year
    ) %>%
    summarise(
        # the n() function counts the number of unique observations we have
        playing_time = n()
    ) %>%
    ungroup()
`summarise()` has grouped output by 'batter', 'game_year', 'game_pk'. You can override using the `.groups` argument.`summarise()` has grouped output by 'batter'. You can override using the `.groups` argument.
plate_appearances
pa_in_year <- plate_appearances %>%
  group_by(batter) %>%
  summarise(
    pa_2021 = sum(playing_time[game_year == 2021], na.rm = TRUE), # Plate appearances for 2021
    pa_2022 = sum(playing_time[game_year == 2022], na.rm = TRUE), # Plate appearances for 2022
    pa_2023 = sum(playing_time[game_year == 2023], na.rm = TRUE)  # Plate appearances for 2023
    ) %>%
  mutate(
    pa_avg = round(rowMeans(select(., pa_2021, pa_2022, pa_2023), na.rm = TRUE)) # Calculate row-wise mean
    )
pa_in_year
NA
pa_in_year <- pa_in_year %>%
  mutate(
    # Is there a steady decrease in plate appearances?
    # Calculate percentage decrease between 2021 and 2022
    decrease_21_22 = (pa_2021 - pa_2022) / pa_2021,
    # Calculate percentage decrease between 2022 and 2023
    decrease_22_23 = (pa_2022 - pa_2023) / pa_2022,
    # Check if both decreases are at least 15%
    decreasing = if_else(
      decrease_21_22 >= 0.15 & decrease_22_23 >= 0.15,
      1,
      0,
      2 # likely got injured or underperformed (# -> 0)
    ),
    
    # Is there a steady increase in plate appearances?
    # Calculate percentage increase between 2021 and 2022
    increase_21_22 = (pa_2022 - pa_2021) / pa_2021,
    # Calculate percentage increase between 2022 and 2023
    increase_22_23 = (pa_2023 - pa_2022) / pa_2022,
    # Check if both increases are at least 15%
    increasing = if_else(
      increase_21_22 >= 0.15 & increase_22_23 >= 0.15,
      1,
      0,
      2 # likely a rookie or comeback from injury (0 -> #)
    ),
    
    # Is the amount of plate appearances constant within 15%
    constant = if_else(
      # if it is increasing or decreasing, then it is not constant
      (increasing == 1) | (decreasing == 1), 
       0,
       if_else(
         # If EITHER difference has an increase or decrease from 0%-15%, it is roughly constant
         (((increase_21_22 < 0.15) & (increase_21_22 > 0)) | 
            ((decrease_21_22 < 0.15) & (decrease_21_22 > 0))) &
           (((increase_22_23 < 0.15) & (increase_22_23 > 0)) | 
              ((decrease_22_23 < 0.15) & (decrease_22_23 > 0))), 
         # if both differences are less than a 15% change it is roughly constant
         1,
         0
         )
       )
    
  ) %>%
  # Optionally, remove intermediate columns
  select(-decrease_21_22, -decrease_22_23, -increase_21_22, -increase_22_23)
pa_in_year
plot(pa_in_year$pa_2021, pa_in_year$pa_2022,
     pch = 19,
     cex = 2,
     col = if_else(pa_in_year$decreasing == 1 | pa_in_year$decreasing == 2, 
                   "red", 
                   if_else(pa_in_year$increasing == 1 | pa_in_year$increasing == 2,
                           "#3d943c",
                           if_else(pa_in_year$constant == 1,
                                   "blue",
                                   "black"))))

plot(pa_in_year$pa_2022, pa_in_year$pa_2023,
     pch = 19,
     cex = 1.5,
     col = if_else(pa_in_year$decreasing == 1, 
                   "red", 
                   if_else(pa_in_year$increasing == 1,
                           "#3d943c",
                           if_else(pa_in_year$constant == 1,
                                   "blue",
                                   "black"))))

summary(factor(pa_in_year$decreasing))
  0   1   2 
696 125 518 
summary(factor(pa_in_year$increasing))
   0    1    2 
1112  115  112 
summary(factor(pa_in_year$constant))
   0    1 
1285   54 
batters_faced <- 
    # start with the savant data
    savant_data  %>%
    # we will group by batter, season, game, and at bat and preserve the 
    group_by(
        pitcher,
        game_year,
        game_pk,
        at_bat_number
    ) %>%
    summarise() %>%
    ungroup() %>%
    # now we have just unique batter, season, game, and at bat observations
    # but, we need to count how many of those there are each season
    # so, we will do another group by and summarise
    group_by(
        pitcher,
        game_year
    ) %>%
    summarise(
        # the n() function counts the number of unique observations we have
        playing_time = n()
    ) %>%
    ungroup()
`summarise()` has grouped output by 'pitcher', 'game_year', 'game_pk'. You can override using the `.groups` argument.`summarise()` has grouped output by 'pitcher'. You can override using the `.groups` argument.
batters_faced

plot(factor(batters_faced$game_year), batters_faced$playing_time, cex = 0.5)

bf_in_year <- batters_faced %>%
  group_by(pitcher) %>%
  summarise(
    bf_2021 = sum(playing_time[game_year == 2021], na.rm = TRUE), # batters faced for 2021
    bf_2022 = sum(playing_time[game_year == 2022], na.rm = TRUE), # batters faced for 2022
    bf_2023 = sum(playing_time[game_year == 2023], na.rm = TRUE)  # batters faced for 2023
    ) %>%
  mutate(
    bf_avg = round(rowMeans(select(., bf_2021, bf_2022, bf_2023), na.rm = TRUE)) # Calculate row-wise mean
    )
bf_in_year
bf_in_year <- bf_in_year %>%
  mutate(
    # Calculate percentage decrease between 2021 and 2022
    decrease_21_22 = (bf_2021 - bf_2022) / bf_2021,
    # Calculate percentage decrease between 2022 and 2023
    decrease_22_23 = (bf_2022 - bf_2023) / bf_2022,
    # Check if both decreases are at least 15%
    decreasing = if_else(
      decrease_21_22 >= 0.15 & decrease_22_23 >= 0.15,
      1,
      0,
      2 # likely injured or under-performed (# -> 0)
    ),
    
    # Calculate percentage increase between 2021 and 2022
    increase_21_22 = (bf_2022 - bf_2021) / bf_2021,
    # Calculate percentage increase between 2022 and 2023
    increase_22_23 = (bf_2023 - bf_2022) / bf_2022,
    # Check if both increases are at least 15%
    increasing = if_else(
      increase_21_22 >= 0.15 & increase_22_23 >= 0.15,
      1,
      0,
      2 # likely rookie or comeback player (0 -> #)
    ),
    
    # Is the amount of batters faced constant within 15%
    constant = if_else(
      # if it is increasing or decreasing, then it is not constant
      (increasing == 1) | (decreasing == 1), 
       0,
       if_else(
         # If EITHER difference has an increase or decrease from 0%-15%, it is roughly constant
         (((increase_21_22 < 0.15) & (increase_21_22 > 0)) | 
            ((decrease_21_22 < 0.15) & (decrease_21_22 > 0))) &
           (((increase_22_23 < 0.15) & (increase_22_23 > 0)) | 
              ((decrease_22_23 < 0.15) & (decrease_22_23 > 0))), 
         # if both differences are less than a 15% change it is roughly constant
         1,
         0
         )
       )
    
  ) %>%
  # Optionally, remove intermediate columns
  select(-decrease_21_22, -decrease_22_23, -increase_21_22, -increase_22_23)
bf_in_year
plot(bf_in_year$bf_2021, bf_in_year$bf_2022,
     pch = 19,
     cex = 2,
     col = if_else(bf_in_year$decreasing == 1 | bf_in_year$decreasing == 2, 
                   "red", 
                   if_else(bf_in_year$increasing == 1 | bf_in_year$increasing == 2,
                           "#3d943c",
                           if_else(bf_in_year$constant == 1,
                                   "blue",
                                   "black"))))

plot(bf_in_year$bf_2022, bf_in_year$bf_2023,
     pch = 19,
     cex = 2,
     col = if_else(bf_in_year$decreasing == 1, 
                   "red", 
                   if_else(bf_in_year$increasing == 1,
                           "#3d943c",
                           if_else(bf_in_year$constant == 1,
                                   "blue",
                                   "black"))))

summary(factor(bf_in_year$decreasing))
  0   1   2 
993 137 253 
summary(factor(bf_in_year$increasing))
   0    1    2 
1026  142  215 
summary(factor(bf_in_year$constant))
   0    1 
1331   52 
LS0tCnRpdGxlOiAiUmVkcyBIYWNrYXRob24gMjAyNSIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3J9CiMgaW5zdGFsbCBkcGx5cgoKaW5zdGFsbC5wYWNrYWdlcygiZHBseXIiKQppbnN0YWxsLnBhY2thZ2VzKCJnZ3Bsb3QyIikKYGBgCgpgYGB7cn0KI2xvYWQgaW4gZHBseXIKCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShkYXRhc2V0cykKYGBgCgpgYGB7cn0KIyByZWFkIHRoZSBjc3YgZmlsZXMKCmxhaG1hbl9wZW9wbGUgPC0gcmVhZC5jc3YoImxhaG1hbl9wZW9wbGUuY3N2IikKc2F2YW50X2RhdGEgPC0gcmVhZC5jc3YoInNhdmFudF9kYXRhXzIwMjFfMjAyMy5jc3YiKQpgYGAKCmBgYHtyfQpoZWFkKGxhaG1hbl9wZW9wbGUpCmhlYWQoc2F2YW50X2RhdGEpCmBgYAoKYGBge3J9CnBsYXRlX2FwcGVhcmFuY2VzIDwtIAogICAgIyBzdGFydCB3aXRoIHRoZSBzYXZhbnQgZGF0YQogICAgc2F2YW50X2RhdGEgICU+JQogICAgIyB3ZSB3aWxsIGdyb3VwIGJ5IGJhdHRlciwgc2Vhc29uLCBnYW1lLCBhbmQgYXQgYmF0IGFuZCBwcmVzZXJ2ZSB0aGUgCiAgICBncm91cF9ieSgKICAgICAgICBiYXR0ZXIsCiAgICAgICAgZ2FtZV95ZWFyLAogICAgICAgIGdhbWVfcGssCiAgICAgICAgYXRfYmF0X251bWJlcgogICAgKSAlPiUKICAgIHN1bW1hcmlzZSgpICU+JQogICAgdW5ncm91cCgpICU+JQogICAgIyBub3cgd2UgaGF2ZSBqdXN0IHVuaXF1ZSBiYXR0ZXIsIHNlYXNvbiwgZ2FtZSwgYW5kIGF0IGJhdCBvYnNlcnZhdGlvbnMKICAgICMgYnV0LCB3ZSBuZWVkIHRvIGNvdW50IGhvdyBtYW55IG9mIHRob3NlIHRoZXJlIGFyZSBlYWNoIHNlYXNvbgogICAgIyBzbywgd2Ugd2lsbCBkbyBhbm90aGVyIGdyb3VwIGJ5IGFuZCBzdW1tYXJpc2UKICAgIGdyb3VwX2J5KAogICAgICAgIGJhdHRlciwKICAgICAgICBnYW1lX3llYXIKICAgICkgJT4lCiAgICBzdW1tYXJpc2UoCiAgICAgICAgIyB0aGUgbigpIGZ1bmN0aW9uIGNvdW50cyB0aGUgbnVtYmVyIG9mIHVuaXF1ZSBvYnNlcnZhdGlvbnMgd2UgaGF2ZQogICAgICAgIHBsYXlpbmdfdGltZSA9IG4oKQogICAgKSAlPiUKICAgIHVuZ3JvdXAoKQpwbGF0ZV9hcHBlYXJhbmNlcwpgYGAKCmBgYHtyfQpwYV9pbl95ZWFyIDwtIHBsYXRlX2FwcGVhcmFuY2VzICU+JQogIGdyb3VwX2J5KGJhdHRlcikgJT4lCiAgc3VtbWFyaXNlKAogICAgcGFfMjAyMSA9IHN1bShwbGF5aW5nX3RpbWVbZ2FtZV95ZWFyID09IDIwMjFdLCBuYS5ybSA9IFRSVUUpLCAjIFBsYXRlIGFwcGVhcmFuY2VzIGZvciAyMDIxCiAgICBwYV8yMDIyID0gc3VtKHBsYXlpbmdfdGltZVtnYW1lX3llYXIgPT0gMjAyMl0sIG5hLnJtID0gVFJVRSksICMgUGxhdGUgYXBwZWFyYW5jZXMgZm9yIDIwMjIKICAgIHBhXzIwMjMgPSBzdW0ocGxheWluZ190aW1lW2dhbWVfeWVhciA9PSAyMDIzXSwgbmEucm0gPSBUUlVFKSAgIyBQbGF0ZSBhcHBlYXJhbmNlcyBmb3IgMjAyMwogICAgKSAlPiUKICBtdXRhdGUoCiAgICBwYV9hdmcgPSByb3VuZChyb3dNZWFucyhzZWxlY3QoLiwgcGFfMjAyMSwgcGFfMjAyMiwgcGFfMjAyMyksIG5hLnJtID0gVFJVRSkpICMgQ2FsY3VsYXRlIHJvdy13aXNlIG1lYW4KICAgICkKcGFfaW5feWVhcgogIApgYGAKCmBgYHtyfQpwYV9pbl95ZWFyIDwtIHBhX2luX3llYXIgJT4lCiAgbXV0YXRlKAogICAgIyBJcyB0aGVyZSBhIHN0ZWFkeSBkZWNyZWFzZSBpbiBwbGF0ZSBhcHBlYXJhbmNlcz8KICAgICMgQ2FsY3VsYXRlIHBlcmNlbnRhZ2UgZGVjcmVhc2UgYmV0d2VlbiAyMDIxIGFuZCAyMDIyCiAgICBkZWNyZWFzZV8yMV8yMiA9IChwYV8yMDIxIC0gcGFfMjAyMikgLyBwYV8yMDIxLAogICAgIyBDYWxjdWxhdGUgcGVyY2VudGFnZSBkZWNyZWFzZSBiZXR3ZWVuIDIwMjIgYW5kIDIwMjMKICAgIGRlY3JlYXNlXzIyXzIzID0gKHBhXzIwMjIgLSBwYV8yMDIzKSAvIHBhXzIwMjIsCiAgICAjIENoZWNrIGlmIGJvdGggZGVjcmVhc2VzIGFyZSBhdCBsZWFzdCAxNSUKICAgIGRlY3JlYXNpbmcgPSBpZl9lbHNlKAogICAgICBkZWNyZWFzZV8yMV8yMiA+PSAwLjE1ICYgZGVjcmVhc2VfMjJfMjMgPj0gMC4xNSwKICAgICAgMSwKICAgICAgMCwKICAgICAgMiAjIGxpa2VseSBnb3QgaW5qdXJlZCBvciB1bmRlcnBlcmZvcm1lZCAoIyAtPiAwKQogICAgKSwKICAgIAogICAgIyBJcyB0aGVyZSBhIHN0ZWFkeSBpbmNyZWFzZSBpbiBwbGF0ZSBhcHBlYXJhbmNlcz8KICAgICMgQ2FsY3VsYXRlIHBlcmNlbnRhZ2UgaW5jcmVhc2UgYmV0d2VlbiAyMDIxIGFuZCAyMDIyCiAgICBpbmNyZWFzZV8yMV8yMiA9IChwYV8yMDIyIC0gcGFfMjAyMSkgLyBwYV8yMDIxLAogICAgIyBDYWxjdWxhdGUgcGVyY2VudGFnZSBpbmNyZWFzZSBiZXR3ZWVuIDIwMjIgYW5kIDIwMjMKICAgIGluY3JlYXNlXzIyXzIzID0gKHBhXzIwMjMgLSBwYV8yMDIyKSAvIHBhXzIwMjIsCiAgICAjIENoZWNrIGlmIGJvdGggaW5jcmVhc2VzIGFyZSBhdCBsZWFzdCAxNSUKICAgIGluY3JlYXNpbmcgPSBpZl9lbHNlKAogICAgICBpbmNyZWFzZV8yMV8yMiA+PSAwLjE1ICYgaW5jcmVhc2VfMjJfMjMgPj0gMC4xNSwKICAgICAgMSwKICAgICAgMCwKICAgICAgMiAjIGxpa2VseSBhIHJvb2tpZSBvciBjb21lYmFjayBmcm9tIGluanVyeSAoMCAtPiAjKQogICAgKSwKICAgIAogICAgIyBJcyB0aGUgYW1vdW50IG9mIHBsYXRlIGFwcGVhcmFuY2VzIGNvbnN0YW50IHdpdGhpbiAxNSUKICAgIGNvbnN0YW50ID0gaWZfZWxzZSgKICAgICAgIyBpZiBpdCBpcyBpbmNyZWFzaW5nIG9yIGRlY3JlYXNpbmcsIHRoZW4gaXQgaXMgbm90IGNvbnN0YW50CiAgICAgIChpbmNyZWFzaW5nID09IDEpIHwgKGRlY3JlYXNpbmcgPT0gMSksIAogICAgICAgMCwKICAgICAgIGlmX2Vsc2UoCiAgICAgICAgICMgSWYgRUlUSEVSIGRpZmZlcmVuY2UgaGFzIGFuIGluY3JlYXNlIG9yIGRlY3JlYXNlIGZyb20gMCUtMTUlLCBpdCBpcyByb3VnaGx5IGNvbnN0YW50CiAgICAgICAgICgoKGluY3JlYXNlXzIxXzIyIDwgMC4xNSkgJiAoaW5jcmVhc2VfMjFfMjIgPiAwKSkgfCAKICAgICAgICAgICAgKChkZWNyZWFzZV8yMV8yMiA8IDAuMTUpICYgKGRlY3JlYXNlXzIxXzIyID4gMCkpKSAmCiAgICAgICAgICAgKCgoaW5jcmVhc2VfMjJfMjMgPCAwLjE1KSAmIChpbmNyZWFzZV8yMl8yMyA+IDApKSB8IAogICAgICAgICAgICAgICgoZGVjcmVhc2VfMjJfMjMgPCAwLjE1KSAmIChkZWNyZWFzZV8yMl8yMyA+IDApKSksIAogICAgICAgICAjIGlmIGJvdGggZGlmZmVyZW5jZXMgYXJlIGxlc3MgdGhhbiBhIDE1JSBjaGFuZ2UgaXQgaXMgcm91Z2hseSBjb25zdGFudAogICAgICAgICAxLAogICAgICAgICAwCiAgICAgICAgICkKICAgICAgICkKICAgIAogICkgJT4lCiAgIyBPcHRpb25hbGx5LCByZW1vdmUgaW50ZXJtZWRpYXRlIGNvbHVtbnMKICBzZWxlY3QoLWRlY3JlYXNlXzIxXzIyLCAtZGVjcmVhc2VfMjJfMjMsIC1pbmNyZWFzZV8yMV8yMiwgLWluY3JlYXNlXzIyXzIzKQpwYV9pbl95ZWFyCmBgYAoKYGBge3J9CnBsb3QocGFfaW5feWVhciRwYV8yMDIxLCBwYV9pbl95ZWFyJHBhXzIwMjIsCiAgICAgcGNoID0gMTksCiAgICAgY2V4ID0gMiwKICAgICBjb2wgPSBpZl9lbHNlKHBhX2luX3llYXIkZGVjcmVhc2luZyA9PSAxIHwgcGFfaW5feWVhciRkZWNyZWFzaW5nID09IDIsIAogICAgICAgICAgICAgICAgICAgInJlZCIsIAogICAgICAgICAgICAgICAgICAgaWZfZWxzZShwYV9pbl95ZWFyJGluY3JlYXNpbmcgPT0gMSB8IHBhX2luX3llYXIkaW5jcmVhc2luZyA9PSAyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAiIzNkOTQzYyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmX2Vsc2UocGFfaW5feWVhciRjb25zdGFudCA9PSAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJibHVlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYmxhY2siKSkpKQpwbG90KHBhX2luX3llYXIkcGFfMjAyMiwgcGFfaW5feWVhciRwYV8yMDIzLAogICAgIHBjaCA9IDE5LAogICAgIGNleCA9IDEuNSwKICAgICBjb2wgPSBpZl9lbHNlKHBhX2luX3llYXIkZGVjcmVhc2luZyA9PSAxLCAKICAgICAgICAgICAgICAgICAgICJyZWQiLCAKICAgICAgICAgICAgICAgICAgIGlmX2Vsc2UocGFfaW5feWVhciRpbmNyZWFzaW5nID09IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICIjM2Q5NDNjIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZfZWxzZShwYV9pbl95ZWFyJGNvbnN0YW50ID09IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImJsdWUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJibGFjayIpKSkpCnN1bW1hcnkoZmFjdG9yKHBhX2luX3llYXIkZGVjcmVhc2luZykpCnN1bW1hcnkoZmFjdG9yKHBhX2luX3llYXIkaW5jcmVhc2luZykpCnN1bW1hcnkoZmFjdG9yKHBhX2luX3llYXIkY29uc3RhbnQpKQpgYGAKCmBgYHtyfQpiYXR0ZXJzX2ZhY2VkIDwtIAogICAgIyBzdGFydCB3aXRoIHRoZSBzYXZhbnQgZGF0YQogICAgc2F2YW50X2RhdGEgICU+JQogICAgIyB3ZSB3aWxsIGdyb3VwIGJ5IGJhdHRlciwgc2Vhc29uLCBnYW1lLCBhbmQgYXQgYmF0IGFuZCBwcmVzZXJ2ZSB0aGUgCiAgICBncm91cF9ieSgKICAgICAgICBwaXRjaGVyLAogICAgICAgIGdhbWVfeWVhciwKICAgICAgICBnYW1lX3BrLAogICAgICAgIGF0X2JhdF9udW1iZXIKICAgICkgJT4lCiAgICBzdW1tYXJpc2UoKSAlPiUKICAgIHVuZ3JvdXAoKSAlPiUKICAgICMgbm93IHdlIGhhdmUganVzdCB1bmlxdWUgYmF0dGVyLCBzZWFzb24sIGdhbWUsIGFuZCBhdCBiYXQgb2JzZXJ2YXRpb25zCiAgICAjIGJ1dCwgd2UgbmVlZCB0byBjb3VudCBob3cgbWFueSBvZiB0aG9zZSB0aGVyZSBhcmUgZWFjaCBzZWFzb24KICAgICMgc28sIHdlIHdpbGwgZG8gYW5vdGhlciBncm91cCBieSBhbmQgc3VtbWFyaXNlCiAgICBncm91cF9ieSgKICAgICAgICBwaXRjaGVyLAogICAgICAgIGdhbWVfeWVhcgogICAgKSAlPiUKICAgIHN1bW1hcmlzZSgKICAgICAgICAjIHRoZSBuKCkgZnVuY3Rpb24gY291bnRzIHRoZSBudW1iZXIgb2YgdW5pcXVlIG9ic2VydmF0aW9ucyB3ZSBoYXZlCiAgICAgICAgcGxheWluZ190aW1lID0gbigpCiAgICApICU+JQogICAgdW5ncm91cCgpCmJhdHRlcnNfZmFjZWQKCnBsb3QoZmFjdG9yKGJhdHRlcnNfZmFjZWQkZ2FtZV95ZWFyKSwgYmF0dGVyc19mYWNlZCRwbGF5aW5nX3RpbWUsIGNleCA9IDAuNSkKYGBgCgpgYGB7cn0KYmZfaW5feWVhciA8LSBiYXR0ZXJzX2ZhY2VkICU+JQogIGdyb3VwX2J5KHBpdGNoZXIpICU+JQogIHN1bW1hcmlzZSgKICAgIGJmXzIwMjEgPSBzdW0ocGxheWluZ190aW1lW2dhbWVfeWVhciA9PSAyMDIxXSwgbmEucm0gPSBUUlVFKSwgIyBiYXR0ZXJzIGZhY2VkIGZvciAyMDIxCiAgICBiZl8yMDIyID0gc3VtKHBsYXlpbmdfdGltZVtnYW1lX3llYXIgPT0gMjAyMl0sIG5hLnJtID0gVFJVRSksICMgYmF0dGVycyBmYWNlZCBmb3IgMjAyMgogICAgYmZfMjAyMyA9IHN1bShwbGF5aW5nX3RpbWVbZ2FtZV95ZWFyID09IDIwMjNdLCBuYS5ybSA9IFRSVUUpICAjIGJhdHRlcnMgZmFjZWQgZm9yIDIwMjMKICAgICkgJT4lCiAgbXV0YXRlKAogICAgYmZfYXZnID0gcm91bmQocm93TWVhbnMoc2VsZWN0KC4sIGJmXzIwMjEsIGJmXzIwMjIsIGJmXzIwMjMpLCBuYS5ybSA9IFRSVUUpKSAjIENhbGN1bGF0ZSByb3ctd2lzZSBtZWFuCiAgICApCmJmX2luX3llYXIKYGBgCgpgYGB7cn0KYmZfaW5feWVhciA8LSBiZl9pbl95ZWFyICU+JQogIG11dGF0ZSgKICAgICMgQ2FsY3VsYXRlIHBlcmNlbnRhZ2UgZGVjcmVhc2UgYmV0d2VlbiAyMDIxIGFuZCAyMDIyCiAgICBkZWNyZWFzZV8yMV8yMiA9IChiZl8yMDIxIC0gYmZfMjAyMikgLyBiZl8yMDIxLAogICAgIyBDYWxjdWxhdGUgcGVyY2VudGFnZSBkZWNyZWFzZSBiZXR3ZWVuIDIwMjIgYW5kIDIwMjMKICAgIGRlY3JlYXNlXzIyXzIzID0gKGJmXzIwMjIgLSBiZl8yMDIzKSAvIGJmXzIwMjIsCiAgICAjIENoZWNrIGlmIGJvdGggZGVjcmVhc2VzIGFyZSBhdCBsZWFzdCAxNSUKICAgIGRlY3JlYXNpbmcgPSBpZl9lbHNlKAogICAgICBkZWNyZWFzZV8yMV8yMiA+PSAwLjE1ICYgZGVjcmVhc2VfMjJfMjMgPj0gMC4xNSwKICAgICAgMSwKICAgICAgMCwKICAgICAgMiAjIGxpa2VseSBpbmp1cmVkIG9yIHVuZGVyLXBlcmZvcm1lZCAoIyAtPiAwKQogICAgKSwKICAgIAogICAgIyBDYWxjdWxhdGUgcGVyY2VudGFnZSBpbmNyZWFzZSBiZXR3ZWVuIDIwMjEgYW5kIDIwMjIKICAgIGluY3JlYXNlXzIxXzIyID0gKGJmXzIwMjIgLSBiZl8yMDIxKSAvIGJmXzIwMjEsCiAgICAjIENhbGN1bGF0ZSBwZXJjZW50YWdlIGluY3JlYXNlIGJldHdlZW4gMjAyMiBhbmQgMjAyMwogICAgaW5jcmVhc2VfMjJfMjMgPSAoYmZfMjAyMyAtIGJmXzIwMjIpIC8gYmZfMjAyMiwKICAgICMgQ2hlY2sgaWYgYm90aCBpbmNyZWFzZXMgYXJlIGF0IGxlYXN0IDE1JQogICAgaW5jcmVhc2luZyA9IGlmX2Vsc2UoCiAgICAgIGluY3JlYXNlXzIxXzIyID49IDAuMTUgJiBpbmNyZWFzZV8yMl8yMyA+PSAwLjE1LAogICAgICAxLAogICAgICAwLAogICAgICAyICMgbGlrZWx5IHJvb2tpZSBvciBjb21lYmFjayBwbGF5ZXIgKDAgLT4gIykKICAgICksCiAgICAKICAgICMgSXMgdGhlIGFtb3VudCBvZiBiYXR0ZXJzIGZhY2VkIGNvbnN0YW50IHdpdGhpbiAxNSUKICAgIGNvbnN0YW50ID0gaWZfZWxzZSgKICAgICAgIyBpZiBpdCBpcyBpbmNyZWFzaW5nIG9yIGRlY3JlYXNpbmcsIHRoZW4gaXQgaXMgbm90IGNvbnN0YW50CiAgICAgIChpbmNyZWFzaW5nID09IDEpIHwgKGRlY3JlYXNpbmcgPT0gMSksIAogICAgICAgMCwKICAgICAgIGlmX2Vsc2UoCiAgICAgICAgICMgSWYgRUlUSEVSIGRpZmZlcmVuY2UgaGFzIGFuIGluY3JlYXNlIG9yIGRlY3JlYXNlIGZyb20gMCUtMTUlLCBpdCBpcyByb3VnaGx5IGNvbnN0YW50CiAgICAgICAgICgoKGluY3JlYXNlXzIxXzIyIDwgMC4xNSkgJiAoaW5jcmVhc2VfMjFfMjIgPiAwKSkgfCAKICAgICAgICAgICAgKChkZWNyZWFzZV8yMV8yMiA8IDAuMTUpICYgKGRlY3JlYXNlXzIxXzIyID4gMCkpKSAmCiAgICAgICAgICAgKCgoaW5jcmVhc2VfMjJfMjMgPCAwLjE1KSAmIChpbmNyZWFzZV8yMl8yMyA+IDApKSB8IAogICAgICAgICAgICAgICgoZGVjcmVhc2VfMjJfMjMgPCAwLjE1KSAmIChkZWNyZWFzZV8yMl8yMyA+IDApKSksIAogICAgICAgICAjIGlmIGJvdGggZGlmZmVyZW5jZXMgYXJlIGxlc3MgdGhhbiBhIDE1JSBjaGFuZ2UgaXQgaXMgcm91Z2hseSBjb25zdGFudAogICAgICAgICAxLAogICAgICAgICAwCiAgICAgICAgICkKICAgICAgICkKICAgIAogICkgJT4lCiAgIyBPcHRpb25hbGx5LCByZW1vdmUgaW50ZXJtZWRpYXRlIGNvbHVtbnMKICBzZWxlY3QoLWRlY3JlYXNlXzIxXzIyLCAtZGVjcmVhc2VfMjJfMjMsIC1pbmNyZWFzZV8yMV8yMiwgLWluY3JlYXNlXzIyXzIzKQpiZl9pbl95ZWFyCmBgYAoKYGBge3J9CnBsb3QoYmZfaW5feWVhciRiZl8yMDIxLCBiZl9pbl95ZWFyJGJmXzIwMjIsCiAgICAgcGNoID0gMTksCiAgICAgY2V4ID0gMiwKICAgICBjb2wgPSBpZl9lbHNlKGJmX2luX3llYXIkZGVjcmVhc2luZyA9PSAxIHwgYmZfaW5feWVhciRkZWNyZWFzaW5nID09IDIsIAogICAgICAgICAgICAgICAgICAgInJlZCIsIAogICAgICAgICAgICAgICAgICAgaWZfZWxzZShiZl9pbl95ZWFyJGluY3JlYXNpbmcgPT0gMSB8IGJmX2luX3llYXIkaW5jcmVhc2luZyA9PSAyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAiIzNkOTQzYyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmX2Vsc2UoYmZfaW5feWVhciRjb25zdGFudCA9PSAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJibHVlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYmxhY2siKSkpKQpwbG90KGJmX2luX3llYXIkYmZfMjAyMiwgYmZfaW5feWVhciRiZl8yMDIzLAogICAgIHBjaCA9IDE5LAogICAgIGNleCA9IDIsCiAgICAgY29sID0gaWZfZWxzZShiZl9pbl95ZWFyJGRlY3JlYXNpbmcgPT0gMSwgCiAgICAgICAgICAgICAgICAgICAicmVkIiwgCiAgICAgICAgICAgICAgICAgICBpZl9lbHNlKGJmX2luX3llYXIkaW5jcmVhc2luZyA9PSAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAiIzNkOTQzYyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmX2Vsc2UoYmZfaW5feWVhciRjb25zdGFudCA9PSAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJibHVlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYmxhY2siKSkpKQpzdW1tYXJ5KGZhY3RvcihiZl9pbl95ZWFyJGRlY3JlYXNpbmcpKQpzdW1tYXJ5KGZhY3RvcihiZl9pbl95ZWFyJGluY3JlYXNpbmcpKQpzdW1tYXJ5KGZhY3RvcihiZl9pbl95ZWFyJGNvbnN0YW50KSkKYGBgCg==